# -*- coding: utf8 -*-
########################################################################
# Copyright (c) 2008 Burdakov Daniel <kreved@kreved.org>               #
#                                                                      #
# This file is part of PyWoW.                                          #
#                                                                      #
# PyWoW is free software: you can redistribute it and/or modify        #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or    #
# (at your option) any later version.                                  #
#                                                                      #
# PyWoW is distributed in the hope that it will be useful,             #
# but WITHOUT ANY WARRANTY; without even the implied warranty of       #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        #
# GNU General Public License for more details.                         #
#                                                                      #
# You should have received a copy of the GNU General Public License    #
# along with PyWoW.     If not, see <http://www.gnu.org/licenses/>.    #
########################################################################

from twisted.internet.protocol import ServerFactory
from realmpacketprotocol import RealmPacketProtocol
import packets
from constants import *
import SRP
import errors
from twisted.internet.defer import Deferred

class RealmServerProtocol(RealmPacketProtocol):
 def connectionMade(self):
  RealmPacketProtocol.connectionMade(self)
  self.packet_handlers = [
  (AUTH_CHALLENGE, packets.CAuthChallenge, self.onAuthChallenge, [NOTHING]),
  (AUTH_PROOF, packets.CAuthProof, self.onAuthProof, [SENT_CHALLENGE]),
  (REALM_LIST, packets.CRealmList, self.onRealmList, [AUTHENTICATED]) ]
 def onAuthChallenge(self, packet):
  response = packets.SAuthChallenge()
  if packet.build in self.factory.valid_builds:
   if self.factory.isBanned(self.transport.getPeer().host, packet.I):
    response.result = BANNED
   else:
    try: self.s, self.v = self.factory.getSV(packet.I)
    except errors.NoSuchUser, username:
     response.result = AUTH_NO_MATCH
     self.send(response)
     return
    self.b, self.B = SRP.server_begin(self.v)
    response.result = AUTH_SUCCESS
    response.B = self.B
    response.g = SRP.g
    response.N = SRP.n
    response.s = self.s
    self.status = SENT_CHALLENGE
    self.AuthPacket = packet
  else:
   response.result = WRONG_BUILD_NUMBER
  self.send(response)
 def onAuthProof(self, packet):
  response = packets.SAuthProof()
  self.K, self.M = SRP.server_key(self.AuthPacket.I, packet.A, self.b, self.B, self.s, self.v)
  if self.M == packet.cM:
   self.status = AUTHENTICATED
   self.factory.addSessionKey(self.AuthPacket.I, self.K)
   response.result = AUTH_SUCCESS
   response.proof = SRP.host_proof(self.K, packet.A, self.M)
  else:
   response.result = AUTH_NO_MATCH
  self.send(response)
 def onRealmList(self, packet):
  d = self.factory.getRealmList(self.AuthPacket.I)
  d.addCallback(self.onRealmListGetted)
  d.addErrback(lambda err: self.onRealmListGetted([]))
 def onRealmListGetted(self, realms):
  response = packets.SRealmList()
  response.realms = realms
  self.send(response)

class RealmServerFactory(ServerFactory):
 """ World of Warcraft realm server
 
 It'll authenticate users, and send them realm list.
 """
 protocol = RealmServerProtocol
 
 def __init__(self):
  self.valid_builds = [8606]
  self.realms = []
  self.keys = {}
 
 def isBanned(self, ip, username):
  """
  Check IP and username for Ban
  
  This function returns True, if user or IP is banned
  """
  return False
 def getSV(self, username):
  """return salt and verifier for specified user
  string: username
  tuple: (string:salt, long:verifier)
  if such user does not exists, it should raise errors.NoSuchUser, username
  """
  raise errors.NoSuchUser, username
 def getRealmList(self, username):
  """
  [Deferred]
  should return list of realms
  each realm is tuple:
  (server_type, locked, status, name, address, populationLevel, charactersCount)
   server_type: 0 = NORMAL; 1 = PVP; 6 = RP; 8 = RPPVP
   lock: 1 - locked; 0 - unlocked
   status: 0 - online, 2 - offline
   name: [string] name of realm
   address: [string] ip:port
   populationLevel: = population / pLimit * 2
   charactersCount: count of this username's chars in this realm
  """
  d = Deferred()
  d.callback([(realm.type, realm.isLocked(username), REALM_ONLINE, realm.name, \
   realm.getAddress(), realm.populationLevel(), realm.amountOfCharacters(username)) for realm in self.realms])
  return d
 def generateSV(self, username, password):
  """This function should be called when new user registers
  It generates salt and verifier, which should be stored in database
  and later loaded by getSV()"""
  return SRP.create_new_verifier(username.upper(), password.upper())
 def addRealm(self, realm):
  self.realms.append(realm)
  realm.realmserver = self
 def addSessionKey(self, username, key):
  """This function is called by protocol, when new user authenticated,
  the session key понадобится for worldserver"""
  self.keys[username] = key
